package com.cj.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cj.common.constant.Constant;
import com.cj.common.exception.BaseException;
import com.cj.common.response.Result;
import com.cj.common.utils.DateUtil;
import com.cj.common.utils.StrUtil;
import com.cj.order.dao.OrderMapper;
import com.cj.order.entity.Order;
import com.cj.order.service.OrderService;
import com.cj.order.service.StockFeignService;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hmily.annotation.HmilyTCC;
import org.dromara.hmily.core.context.HmilyContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author cheng jun
 * @Description: 目前Hmily是已经完成了对空回滚、悬挂、幂等性问题的自动处理，无需开发者自行处理
 * @Date 2021/7/25 15:29
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private StockFeignService stockFeignService;

    @Override
    public boolean placeOrder(Order order) {
        order.setOrderId(StrUtil.getUuid32());
        order.setPayType(Constant.UNPAID);
        Date currentDate = DateUtil.getCurrentDate();
        order.setCreationTime(currentDate);
        order.setUpdateTime(currentDate);
        return this.save(order);
    }

    /**
     * 只要标记@Hmily就是try方法，在注解中指定confirm、cancel两个方法的名字
     * @param order
     * @return
     */
    @Override
    @Transactional(rollbackFor = BaseException.class)
    @HmilyTCC(confirmMethod="commit",cancelMethod="rollback")
    public boolean pay(Order order) {
        // 参数校验
        Assert.notNull(order, "参数为空");
        String commodityId = order.getCommodityId();
        long commodityNum = order.getCommodityNum();
        Assert.notNull(commodityId, "商品id不能为空");
        Assert.notNull(commodityNum, "商品数量不能为空");

        log.info("order try begin 开始执行...");

        // 更新订单
        if(updateOrder(order, Constant.PAYMENTS)) {
            // 更新订单失败
            throw new BaseException("bank1 try 更新订单失败");
        }

        // 远程调用库存服务
        Map<String, Object> stockMap = new HashMap<>();
        stockMap.put("commodityId", commodityId);
        stockMap.put("commodityNum", commodityNum);
        Result stockFeignResult = stockFeignService.deleteStock(stockMap);
        if(0 != stockFeignResult.getCode()){
            throw new RuntimeException("bank1 远程调用库存服务失败");
        }

        log.info("order try end 结束执行...");

        return true;
    }

    /**
     * confirm方法
     * @param order
     */
    @Transactional(rollbackFor = BaseException.class)
    public boolean commit(Order order){
        log.info("order confirm begin 开始执行...");

        // 更新订单状态
        boolean flag = updateOrder(order, Constant.PAID);

        log.info("order confirm end 结束执行...");

        return flag;
    }



    /** cancel方法
     * 	cancel幂等校验
     * 	cancel空回滚处理
     * 	增加可用余额
     * @param order
     */
    @Transactional(rollbackFor = BaseException.class)
    public boolean rollback(Order order) {
        log.info("order cancel begin 开始执行...");

        // 更新订单状态
        boolean flag = updateOrder(order, Constant.UNPAID);

        log.info("order cancel end 结束执行...");

        return flag;
    }

    /**
     * 更新订单
     * @param order
     * @return
     */
    public boolean updateOrder(Order order, String type) {
        QueryWrapper<Order> queryWrapper = new QueryWrapper();
        queryWrapper.eq("pay_type", type);
        return this.update(order, queryWrapper);
    }
}
